package com.smap.layer;

import java.util.ArrayList;
import java.util.List;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.Context2d.LineCap;
import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
import com.smap.core.Bbox;
import com.smap.core.XY;
import com.smap.vector.Feature;
import com.smap.vector.Geometry;
import com.smap.vector.LineString;
import com.smap.vector.Point;
import com.smap.vector.Polygon;
import com.smap.vector.Style;

/**
 * need to have some kind of r_tree index to improve performance
 * 
 * @author shen
 * 
 */
public class VectorLayer extends CanvasLayer {
	public List<Feature> feats = new ArrayList<Feature>();

	private XY drawingOffset;

	public void add(Feature feat) {
		feats.add(feat);
	}

	public Feature select(XY screenXY) {
		Feature selectedFeat = null;

		XY.TOLERANCE = 10;
		for (Feature feat : feats) {
			boolean contains = feat.screenGeom.contains(screenXY);
			// System.out.println(screenXY+"-"+feat.screenGeom+"="+contains);
			if (contains) {
				selectedFeat = feat;
				break;
			}
		}
		XY.TOLERANCE = 0;
		return selectedFeat;
	}

	/**
	 * draw screen
	 */
	public void draw() {
		clearScreen();
		drawingOffset = this.getCanvasOffset();
		drawingOffset.x = -drawingOffset.x;
		drawingOffset.y = -drawingOffset.y;
		for (Feature feat : feats) {
			feat.createScreen(this.map);
		}
		for (Feature feat : feats) {
			if (inMap(feat)) {
				draw(feat, feat.style);
				drawLabel(feat, feat.style);
			}
		}
	}

	public boolean inMap(Feature feat) {
		boolean inMap = false;
		Bbox enve = feat.geom.envelope;
		if (enve.overlap(map.getExtent())) {
			inMap = true;
		}
		return inMap;
	}

	public void drawLabel(Feature feat, Style style) {
		String label = feat.properties.get("label");
		if (label == null) {
			return;
		}
		Context2d ctx = this.getCtx();
		ctx.setLineWidth(style.stroke_width);
		ctx.setStrokeStyle("white");
		XY p = new XY(feat.screenGeom.getCentroid()).move(drawingOffset);
		ctx.setFont(style.label_font);
		ctx.setFillStyle(style.label_color);
		ctx.strokeText(label, p.x - 10, p.y + 20);
		ctx.fillText(label, p.x - 10, p.y + 20);

	}

	public void draw(Feature feat, Style style) {
		Geometry geom = feat.screenGeom;
		draw(geom, style);
		if (feat.status == 1) {// creating, draw all vertex
			for (XY xy : geom.coordinates) {
				draw(new Point(xy), style);
			}
		}
	}

	public void draw(Geometry geom, Style style) {
		if (style == null) {
			style = new Style();
		}
		Context2d ctx = this.getCtx();
		ctx.setLineWidth(style.stroke_width);
		ctx.setLineCap(LineCap.ROUND);
		ctx.setLineJoin(LineJoin.ROUND);
		if (geom instanceof Point) {
			XY p = new XY(geom.coordinates.get(0)).move(drawingOffset);
			ctx.beginPath();
			ctx.arc(p.x, p.y, style.point_radius, 0, Math.PI * 2, true);
			ctx.closePath();
			ctx.setFillStyle(style.fill_color);
			ctx.setGlobalAlpha(style.fill_opacity);
			ctx.fill();
			ctx.setStrokeStyle(style.stroke_color);
			ctx.setGlobalAlpha(style.stroke_opacity);
			ctx.stroke();
		} else if (geom instanceof LineString) {
			// need to make it pretty!
			ctx.beginPath();
			XY start = null;
			for (XY theP : geom.coordinates) {
				XY p = new XY(theP).move(drawingOffset);
				if (start == null) {
					start = p;
					ctx.moveTo(p.x, p.y);
				} else {
					ctx.lineTo(p.x, p.y);
				}
			}
			ctx.setStrokeStyle(style.stroke_color);
			ctx.setGlobalAlpha(style.fill_opacity);
			ctx.setLineWidth(style.line_width);
			ctx.stroke();
			if (style.line_width > 1) {
				ctx.setStrokeStyle(style.fill_color);
				ctx.setGlobalAlpha(style.stroke_opacity);
				ctx.setLineWidth(style.line_width - style.stroke_width * 2);
				ctx.stroke();
			}
		} else if (geom instanceof Polygon) {
			ctx.beginPath();
			XY start = null;
			for (XY theP : geom.coordinates) {
				XY p = new XY(theP).move(drawingOffset);
				if (start == null) {
					start = p;
					ctx.moveTo(p.x, p.y);
				} else {
					ctx.lineTo(p.x, p.y);
				}
			}
			ctx.closePath();
			ctx.setFillStyle(style.fill_color);
			ctx.setGlobalAlpha(style.fill_opacity);
			ctx.fill();
			ctx.setStrokeStyle(style.stroke_color);
			ctx.setGlobalAlpha(style.stroke_opacity);
			ctx.stroke();
		}
	}

	@Override
	public void getInfo(int x, int y, InfoHandler handler) {
		Feature feat = select(new XY(x, y));
		String ret = "";
		if (feat != null) {
			ret = feat.properties.toString();
		}
		handler.execute(ret);
	}

}
